package com.myzl.coal.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.myzl.coal.client.BaseHandler;
import com.myzl.coal.client.CacheData;
import com.myzl.coal.domain.*;
import com.myzl.coal.mapper.DeviceConfigMapper;
import com.myzl.coal.mapper.DeviceGroupMapper;
import com.myzl.coal.mapper.DeviceMapper;
import com.myzl.coal.mongo.component.MongoComponent;
import com.myzl.coal.mongo.domain.HistoryData;
import com.myzl.coal.service.IDeviceProtocolService;
import com.myzl.coal.service.IDeviceService;
import com.myzl.coal.service.IRealTimeDataService;
import com.myzl.common.constant.CacheConstants;
import com.myzl.common.constant.LedCacheKeyConstants;
import com.myzl.common.core.domain.AjaxResult;
import com.myzl.common.core.domain.entity.SysDictData;
import com.myzl.common.core.redis.RedisCache;
import com.myzl.common.enums.*;
import com.myzl.common.utils.DateUtils;
import com.myzl.common.utils.DictUtils;
import com.myzl.common.utils.JSONUtil;
import com.myzl.common.utils.StringUtils;
import com.myzl.common.utils.spring.SpringUtils;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 设备表Service业务层处理
 *
 * @author myzl
 * @date 2022-09-01
 */
@Service
@Data
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {

    private final DeviceMapper deviceMapper;
    private final DeviceGroupMapper deviceGroupMapper;
    private final DeviceConfigMapper deviceConfigMapper;
    private final RedisTemplate<String, String> redisTemplate;
    private final IRealTimeDataService realtimeDataService;
    private final IDeviceProtocolService deviceProtocolService;
    private final MongoComponent mongoComponent;
    private final RedisCache redisCache;

//    @Lazy
//    @Autowired
//    private StartNettyServer startNettyServer;

    @PostConstruct
    private void initCamera() {
        try {
            List<Device> deviceList = deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                    .eq(Device::getDeviceType, DeviceTypeEnum.CAMERA.getCode()));
            for (Device device : deviceList) {
                SpringUtils.getBean(RedisCache.class).deleteObject(CacheConstants.CAMERA_KEY + device.getId());
            }

            List<Device> ledDeviceList = this.getDeviceByType(DeviceTypeEnum.LED_SCREEN.getCode());
            ledDeviceList.forEach(e -> {
                this.ledConfigCache(e);
            });

        } catch (Exception e) {
            log.error("初始化摄像头异常", e);
        }
    }

    /**
     * 查询设备表
     *
     * @param id 设备表主键
     * @return 设备表
     */
    @Override
    public Device selectDeviceById(Integer id) {
        Device device = deviceMapper.selectDeviceById(id);
        List<RealTimeData> realTimeDataList = realtimeDataService.list(new LambdaQueryWrapper<RealTimeData>()
                .in(RealTimeData::getDeviceId, device.getId())
                .in(RealTimeData::getDictValue, DeviceCommandEnum.VARIABLE_SPEED.getCode(), DeviceCommandEnum.OPERATE_MODE.getCode(), DeviceCommandEnum.SPEED.getCode(), DeviceCommandEnum.CURRENT_DENSITY.getCode()));
        setValue(Arrays.asList(device), realTimeDataList);
        return device;
    }

    /**
     * 查询设备表列表
     *
     * @param device 设备表
     * @return 设备表
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        List<Device> deviceList = deviceMapper.selectDeviceList(device);
        List<Integer> ids = deviceList.stream().filter(d -> DeviceTypeEnum.DOUBLE_ORDER.getCode().equals(d.getDeviceType())).map(Device::getId).collect(Collectors.toList());
        if (!ids.isEmpty()) {
            List<RealTimeData> realTimeDataList = realtimeDataService.list(new LambdaQueryWrapper<RealTimeData>()
                    .in(RealTimeData::getDeviceId, ids)
                    .in(RealTimeData::getDictValue, DeviceCommandEnum.VARIABLE_SPEED.getCode(), DeviceCommandEnum.OPERATE_MODE.getCode(), DeviceCommandEnum.SPEED.getCode(), DeviceCommandEnum.CURRENT_DENSITY.getCode()));

            setValue(deviceList, realTimeDataList);
        }
        return deviceList;
    }

    private void setValue(List<Device> deviceList, List<RealTimeData> realTimeDataList) {
        Map<Integer, Map<Integer, String>> map = realTimeDataList.stream().collect(Collectors.groupingBy(RealTimeData::getDeviceId, Collectors.toMap(RealTimeData::getDictValue, RealTimeData::getDataValue)));
        Map<Integer, Device> deviceMap = deviceList.stream().collect(Collectors.toMap(Device::getId, Function.identity()));

        map.forEach((k, v) -> {
            String operate_mode = v.get(DeviceCommandEnum.OPERATE_MODE.getCode());
            operate_mode = ObjectUtils.isEmpty(operate_mode) ? OperateModeEnum.UNIFORM_SPEED.getCode() : operate_mode;
            Device device1 = deviceMap.get(k);
            if (OperateModeEnum.UNIFORM_SPEED.getCode().equals(operate_mode)) {
                device1.setSpeed(v.get(DeviceCommandEnum.SPEED.getCode()));
            } else {
                device1.setSpeed(v.get(DeviceCommandEnum.VARIABLE_SPEED.getCode()));
            }
            device1.setDensity(v.get(DeviceCommandEnum.CURRENT_DENSITY.getCode()));

        });
    }

    @Override
    @Cacheable(value = "device", key = "#id")
    public Device cacheDeviceById(Integer id) {
        Device device = deviceMapper.selectDeviceById(id);
        return device;
    }

    @Override
    @Cacheable(value = "device", key = "'#ip'+'#port'")
    public Device cacheDeviceByUrl(String ip, Integer port) {
        Device device = new Device();
        device.setIp(ip);
        device.setPort(port);
        List<Device> deviceList = deviceMapper.selectDeviceList(device);
        if (CollectionUtils.isEmpty(deviceList)) {
            return null;
        }
        return deviceList.get(0);
    }

    private void handleDensityAndSpeed(Device device, List<RealTimeData> realTimeDataList) {
        for (RealTimeData realTimeData : realTimeDataList) {
            if (device.getId().equals(realTimeData.getDeviceId()) && realTimeData.getDictValue().equals(DeviceCommandEnum.SPEED.getCode())) {
                device.setSpeed(realTimeData.getDataValue());
            }
            if (device.getId().equals(realTimeData.getDeviceId()) && realTimeData.getDictValue().equals(DeviceCommandEnum.CURRENT_DENSITY.getCode())) {
                device.setDensity(realTimeData.getDataValue());
            }
        }
    }

    /**
     * 新增设备表
     *
     * @param device 设备表
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertDevice(Device device) {
        DeviceGroup deviceGroup = handleDeviceGroup(device);
        device.setDeviceGroup(deviceGroup.getId());
        int result = deviceMapper.insertDevice(device);
        if (DeviceTypeEnum.CAMERA.getCode().equals(device.getDeviceType())) {
            return result;
        }
//        startNettyServer.startDevice(device.getId());
        return result;
    }

    /**
     * 修改设备表
     *
     * @param device 设备表
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = "device", key = "#device.id"),
            @CacheEvict(value = "device", key = "'#device.ip'+'#device.port'")
    })
    public int updateDevice(Device device) {
        DeviceGroup deviceGroup = handleDeviceGroup(device);
        device.setDeviceGroup(deviceGroup.getId());

        Device oldDevice = deviceMapper.selectDeviceById(device.getId());
        int i = deviceMapper.updateDevice(device);
        if (DeviceTypeEnum.CAMERA.getCode().equals(device.getDeviceType())) {
            return i;
        }
        String oldKey = BaseHandler.getKey(oldDevice.getIp(), oldDevice.getPort());
        String newKey = BaseHandler.getKey(device.getIp(), device.getPort());
        if (!Objects.equals(oldKey, newKey)) {
//            startNettyServer.stopDevice(oldDevice);
        }
        CacheData.clear();
        DeviceProtocol deviceProtocol = deviceProtocolService.cacheByDeviceType(device.getDeviceType());
        if (Objects.equals(CommunicationProtocolEnum.TCP.getCode(), deviceProtocol.getCommunicationProtocol()) || Objects.equals(CommunicationProtocolEnum.UDP.getCode(), deviceProtocol.getCommunicationProtocol())) {
//            startNettyServer.startDevice(device);
        }

        return i;
    }

    /**
     * 批量删除设备表
     *
     * @param ids 需要删除的设备表主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(String[] ids) {
        return deviceMapper.deleteDeviceByIds(ids);
    }

    /**
     * 删除设备表信息
     *
     * @param id 设备表主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(String id) {
        return deviceMapper.deleteDeviceById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult configDensity(Device device) {
        DeviceConfig lastDeviceConfig = deviceConfigMapper.selectOne(new LambdaQueryWrapper<DeviceConfig>()
                .eq(DeviceConfig::getDeviceId, device.getId())
                .orderByDesc(DeviceConfig::getCreateTime).last("limit 1"));

        if (StringUtils.isNotNull(lastDeviceConfig)) {
            lastDeviceConfig.setEndTime(DateUtils.getNowDate());
            deviceConfigMapper.updateDeviceConfig(lastDeviceConfig);
        }
        DeviceConfig deviceConfig = new DeviceConfig();
        deviceConfig.setDeviceId(device.getId());
        if (StringUtils.isNotNull(device.getSpeed())) {
            deviceConfig.setSpeed(device.getSpeed());
        } else {
            if (StringUtils.isNotNull(lastDeviceConfig)) {
                deviceConfig.setSpeed(lastDeviceConfig.getSpeed());
            }
        }
        if (StringUtils.isNotNull(device.getDensity())) {
            deviceConfig.setDensity(device.getDensity());
        } else {
            if (StringUtils.isNotNull(lastDeviceConfig)) {
                deviceConfig.setDensity(lastDeviceConfig.getDensity());
            }
        }
        deviceConfigMapper.insertDeviceConfig(deviceConfig);
        List<SysDictData> binocularRadarFunction = DictUtils.getDictCache("binocular_radar_function");
        binocularRadarFunction = binocularRadarFunction.stream().filter(sysDictData ->
                DictDataType.PARAM.getCode().equals(sysDictData.getDataType()))
                .collect(Collectors.toList());
        for (SysDictData dictData : binocularRadarFunction) {
            if (dictData.getDictValue().equals(String.valueOf(DeviceCommandEnum.CURRENT_DENSITY.getCode()))) {
                saveRealTimeData(device.getId(), device.getDeviceType(), Integer.parseInt(dictData.getDictValue())
                        , dictData.getValueUnit(), device.getDensity());
            }
        }

        CacheData.clear();
        return AjaxResult.success();
    }

    @Override
    public AjaxResult getTrendChart(Long deviceId) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime currentStartClassTime = now;
        LocalDateTime currentEndClassTime = now;
        String day = LocalDateTimeUtil.format(now, DatePattern.NORM_DATE_PATTERN);

        List<SysDictData> dictCache = DictUtils.getDictCache("everyday_shift_time");
        for (int i = 0; i < dictCache.size(); i++) {
            SysDictData sysDictData = dictCache.get(i);
            String dictValue = sysDictData.getDictValue();
            String[] classTime = dictValue.split("-");
            String start = classTime[0];
            String end = classTime[1];
            LocalDateTime startClassTime = LocalDateTimeUtil.parse(day + " " + start, DatePattern.NORM_DATETIME_PATTERN);
            LocalDateTime endClassTime = LocalDateTimeUtil.parse(day + " " + end, DatePattern.NORM_DATETIME_PATTERN);
            if (now.isAfter(startClassTime) && now.isBefore(endClassTime)) {
                currentStartClassTime = startClassTime;
                currentEndClassTime = endClassTime;
            }
        }

        Date startTime = Date.from(currentStartClassTime.atZone(ZoneId.systemDefault()).toInstant());
        Date endTime = Date.from(currentEndClassTime.atZone(ZoneId.systemDefault()).toInstant());
        List<RealTimeData> realtimeData = realtimeDataService.queryDataByDate(deviceId, startTime, endTime);

        return AjaxResult.success(realtimeData);
    }

    @Override
    public List<Device> getDeviceByType(int deviceType) {
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceType, deviceType);
        List<Device> list = list(queryWrapper);
        return list;
    }

    @Override
    public List<Device> getDeviceByGroup(Integer groupType, Integer deviceType) {
        LambdaQueryWrapper<DeviceGroup> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeviceGroup::getGroupType, groupType);
        List<DeviceGroup> deviceGroups = deviceGroupMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(deviceGroups)) {
            return Collections.emptyList();
        }
        List<Integer> groups = deviceGroups.stream().map(DeviceGroup::getId).collect(Collectors.toList());

        LambdaQueryWrapper<Device> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.in(Device::getDeviceGroup, groups);
        if (Objects.nonNull(deviceType)) {
            deviceWrapper.eq(Device::getDeviceType, deviceType);
        }
        List<Device> devices = deviceMapper.selectList(deviceWrapper);
        return devices;
    }

    @Override
    public List<Device> getDeviceByGroupId(Integer groupId, Integer deviceType) {
        LambdaQueryWrapper<Device> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.in(Device::getDeviceGroup, groupId);
        deviceWrapper.eq(Device::getDeviceType, deviceType);
        List<Device> devices = deviceMapper.selectList(deviceWrapper);
        return devices;
    }

    @Override
    public List<Device> getCamera(Integer deviceId) {
        Device device = deviceMapper.selectDeviceById(deviceId);
        List<Device> cameraList = deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, DeviceTypeEnum.CAMERA.getCode())
                .eq(Device::getDeviceGroup, device.getDeviceGroup()));
        if (ObjectUtils.isEmpty(cameraList)) {
            return new ArrayList<>();
        }
        return cameraList;
    }

    @Override
    public AjaxResult getSieveList(String parentGroupId) {
        Device device = new Device();
        device.setDeviceType(DeviceTypeEnum.LIDAR.getCode());
        device.setParentGroupId(parentGroupId);
        List<Device> deviceList = deviceMapper.selectDeviceList(device);
        deviceList = ObjectUtils.isEmpty(deviceList) ? new ArrayList<>() : deviceList;
        Map<Integer, Device> cameraMap = getCameraMap(deviceList);
        return AjaxResult.success(deviceList).put("cameraData", cameraMap);
    }

    private Map<Integer, Device> getCameraMap(List<Device> deviceList) {
        Map<Integer, Device> cameraMap = new HashMap<>(16);
        for (Device device : deviceList) {
            Device camera = deviceMapper.selectOne(new LambdaQueryWrapper<Device>()
                    .eq(Device::getDeviceType, DeviceTypeEnum.CAMERA.getCode())
                    .eq(Device::getDeviceGroup, device.getDeviceGroup())
                    .last("limit 1"));
            camera = ObjectUtils.isEmpty(camera) ? new Device() : camera;
            cameraMap.put(device.getId(), camera);
        }
        return cameraMap;
    }

    @Override
    public Map<Integer, String> getDeviceParam(String deviceId, List<String> dictValues) {
        Map<Integer, String> result = new HashMap<>(16);
        List<RealTimeData> list = realtimeDataService.list(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId)
                .in(RealTimeData::getDictValue, dictValues));
        if (!list.isEmpty()) {
            result = list.stream().collect(Collectors.toMap(RealTimeData::getDictValue, RealTimeData::getDataValue, (oldValue, newValue) -> newValue));
        }
        return result;
    }

    @Override
    public AjaxResult saveDeviceParam(Map<String, String> deviceParam) {
        List<RealTimeData> deviceParamData = new ArrayList<>();
        List<HistoryData> deviceParamHistoryData = new ArrayList<>();
        String deviceId = deviceParam.get("deviceId");
        String deviceType = deviceParam.get("deviceType");
        List<SysDictData> paramType = new ArrayList<>();
        if (DeviceTypeEnum.DOUBLE_ORDER.getCode().equals(Integer.valueOf(deviceType))) {
            List<SysDictData> binocularRadarFunction = DictUtils.getDictCache("binocular_radar_function");
            paramType = binocularRadarFunction.stream().filter(sysDictData -> DictDataType.PARAM.getCode().equals(sysDictData.getDataType())).collect(Collectors.toList());
        } else if (DeviceTypeEnum.LIDAR.getCode().equals(Integer.valueOf(deviceType))) {
            List<SysDictData> sieveRadarFunction = DictUtils.getDictCache("sieve_radar_function");
            paramType = sieveRadarFunction.stream().filter(sysDictData -> DictDataType.PARAM.getCode().equals(sysDictData.getDataType())).collect(Collectors.toList());
        }
        if (!paramType.isEmpty()) {
            for (SysDictData dictData : paramType) {
                handleDeviceParam(deviceParamData, deviceParamHistoryData, deviceParam, dictData);
            }
        }
        if (DeviceTypeEnum.DOUBLE_ORDER.getCode().equals(Integer.valueOf(deviceType))) {
            //双目设备保存一份配置记录
            saveDensityAndSpeed(deviceParam);
            handleDensityHistory(deviceParamHistoryData);
        }
        if (!deviceParamHistoryData.isEmpty()) {
            mongoComponent.saveBatch(deviceParamHistoryData, HistoryData.class);
        }
        if (!deviceParamData.isEmpty()) {
            realtimeDataService.saveOrUpdateBatch(deviceParamData);
        }
        CacheData.clear();
        return AjaxResult.success();
    }

    @Override
    public Device getDevice(Device device) {
        return deviceMapper.selectOne(new LambdaQueryWrapper<Device>()
                .eq(Device::getId, device.getId())
                .eq(Device::getDeviceType, device.getDeviceType()));
    }

    @Override
    public AjaxResult getLEDDevice(Integer deviceId) {
        AjaxResult ajaxResult = AjaxResult.success();
        Device scaleDevice = selectDeviceById(deviceId);
        ajaxResult.put("scale", scaleDevice);
        Device LEDDevice = deviceMapper.selectOne(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceGroup, scaleDevice.getDeviceGroup())
                .eq(Device::getDeviceType, DeviceTypeEnum.LED_SCREEN.getCode()));
        ajaxResult.put("led", LEDDevice);
        return ajaxResult;
    }

    @Override
    public List<Device> getDeviceByDeviceTypeList(Integer deviceType) {
        return deviceMapper.selectList(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, deviceType)
                .orderByDesc(Device::getId));
    }

    @Override
    public Device getDeviceByDeviceType(Integer deviceType) {
        return deviceMapper.selectOne(new LambdaQueryWrapper<Device>()
                .eq(Device::getDeviceType, deviceType)
                .orderByDesc(Device::getId)
                .last("limit 1"));
    }

    @Override
    public boolean ledConfigCache(Device device) {
        JSONObject json = JSONObject.parseObject(device.getDeviceConfig());
        String color = json.getString(LedCacheKeyConstants.LED_COLOR);
        redisCache.setCacheObject(redisCache.getLedCacheKey(LedCacheKeyConstants.LED_COLOR), color);
        List<Integer> contents = json.getList(LedCacheKeyConstants.LED_CONTENT, Integer.class);
        redisCache.deleteObject(redisCache.getLedCacheKey(LedCacheKeyConstants.LED_CONTENT));
        redisCache.setCacheList(redisCache.getLedCacheKey(LedCacheKeyConstants.LED_CONTENT), contents);
        return true;
    }

    @Override
    public boolean validateDensity(Device device) {
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(device.getId()),
                Criteria.where("dictValue").is(DeviceCommandEnum.CURRENT_DENSITY.getCode())
        );
        Sort descSort = Sort.by(Sort.Order.desc("createTime"));
        List<HistoryData> densityList = mongoComponent.selectList(criteria, 1, descSort, HistoryData.class);
        if (CollUtil.isEmpty(densityList)){
            return true;
        }
        HistoryData historyData = densityList.get(0);
        if (device.getDensity().equals(String.valueOf(historyData.getDataValue()))) {
            return false;
        }
        return true;
    }

    @Override
    public Device replaceConfig(Device device) {
        Device sourceDevice = deviceMapper.selectDeviceById(device.getId());
        JSONObject source = new JSONObject();
        JSONObject target = new JSONObject();
        if (StrUtil.isNotEmpty(sourceDevice.getDeviceConfig())) {
            source = JSONObject.parse(sourceDevice.getDeviceConfig());
        }
        if (StrUtil.isNotEmpty(device.getDeviceConfig())) {
            target = JSONObject.parse(device.getDeviceConfig());
        }
        JSONObject result = JSONUtil.replace(source, target);
        device.setDeviceConfig(result.toString());
        return device;
    }

    private void saveDensityAndSpeed(Map<String, String> deviceParam) {
        String deviceId = deviceParam.get("deviceId");
        String speed = deviceParam.get(String.valueOf(DeviceCommandEnum.SPEED.getCode()));
        String density = deviceParam.get(String.valueOf(DeviceCommandEnum.CURRENT_DENSITY.getCode()));
        DeviceConfig lastDeviceConfig = deviceConfigMapper.selectOne(new LambdaQueryWrapper<DeviceConfig>()
                .eq(DeviceConfig::getDeviceId, deviceId)
                .orderByDesc(DeviceConfig::getCreateTime).last("limit 1"));

        if (StringUtils.isNotNull(lastDeviceConfig)) {
            lastDeviceConfig.setEndTime(DateUtils.getNowDate());
            deviceConfigMapper.updateDeviceConfig(lastDeviceConfig);
        }
        DeviceConfig deviceConfig = new DeviceConfig();
        deviceConfig.setDeviceId(Integer.valueOf(deviceId));
        if (StringUtils.isNotNull(speed)) {
            deviceConfig.setSpeed(speed);
        } else {
            if (StringUtils.isNotNull(lastDeviceConfig)) {
                deviceConfig.setSpeed(lastDeviceConfig.getSpeed());
            }
        }
        if (StringUtils.isNotNull(density)) {
            deviceConfig.setDensity(density);
        } else {
            if (StringUtils.isNotNull(lastDeviceConfig)) {
                deviceConfig.setDensity(lastDeviceConfig.getDensity());
            }
        }
        deviceConfigMapper.insertDeviceConfig(deviceConfig);
    }

    private void handleDeviceParam(List<RealTimeData> deviceParamData, List<HistoryData> deviceParamHistoryData, Map<String, String> deviceParam, SysDictData dictData) {
        String deviceId = deviceParam.get("deviceId");
        String deviceType = deviceParam.get("deviceType");
        String dictValue = dictData.getDictValue();
        String dataValue = deviceParam.get(dictData.getDictValue());

        HistoryData historyData = new HistoryData();
        RealTimeData deviceParamOne = realtimeDataService.getOne(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId).eq(RealTimeData::getDictValue, dictValue));

        if (StringUtils.isNull(deviceParamOne)) {
            deviceParamOne = new RealTimeData();
        }
        deviceParamOne.setDictValue(Integer.valueOf(dictValue));
        deviceParamOne.setDeviceType(Integer.valueOf(deviceType));
        deviceParamOne.setDeviceId(Integer.valueOf(deviceId));
        deviceParamOne.setDataValue(dataValue);
        deviceParamOne.setDataUnit(dictData.getValueUnit());
        deviceParamData.add(deviceParamOne);
        BeanUtils.copyProperties(deviceParamOne, historyData);
        historyData.initBasic();
        deviceParamHistoryData.add(historyData);
    }

    private void saveRealTimeData(Integer deviceId, Integer deviceType, Integer dictValue, String dataUnit, String dataValue) {
        RealTimeData realTimeData = realtimeDataService.getOne(new LambdaQueryWrapper<RealTimeData>()
                .eq(RealTimeData::getDeviceId, deviceId).eq(RealTimeData::getDictValue, dictValue));

        if (StringUtils.isNull(realTimeData)) {
            realTimeData = new RealTimeData();
        }
        HistoryData historyData = new HistoryData();

        realTimeData.setDeviceId(deviceId);
        realTimeData.setDictValue(dictValue);
        realTimeData.setDeviceType(deviceType);
        realTimeData.setDataValue(dataValue);
        realTimeData.setDataUnit(dataUnit);

        BeanUtils.copyProperties(realTimeData, historyData);
        historyData.initBasic();
        historyData.setStartTime(DateUtils.getNowDate());
        changeLastDensityHistory(historyData);
        mongoComponent.insertOne(historyData);
        realtimeDataService.saveOrUpdate(realTimeData);
    }

    private DeviceGroup handleDeviceGroup(Device device) {
        DeviceGroup parentDeviceGroup = deviceGroupMapper.selectOne(new LambdaQueryWrapper<DeviceGroup>()
                .eq(DeviceGroup::getParentId, 0)
                .eq(DeviceGroup::getGroupName, device.getParentGroupName())
                .last("limit 1"));
        if (ObjectUtils.isEmpty(parentDeviceGroup)) {
            parentDeviceGroup = new DeviceGroup();
            parentDeviceGroup.setGroupType(device.getDeviceGroupTye());
            parentDeviceGroup.setGroupName(device.getParentGroupName());
            deviceGroupMapper.insertDeviceGroup(parentDeviceGroup);
        }

        DeviceGroup childDeviceGroup = deviceGroupMapper.selectOne(new LambdaQueryWrapper<DeviceGroup>()
                .eq(DeviceGroup::getParentId, parentDeviceGroup.getId())
                .eq(DeviceGroup::getGroupName, device.getChildGroupName())
                .last("limit 1"));
        if (ObjectUtils.isEmpty(childDeviceGroup)) {
            childDeviceGroup = new DeviceGroup();
            childDeviceGroup.setParentId(parentDeviceGroup.getId());
            childDeviceGroup.setGroupType(device.getDeviceGroupTye());
            childDeviceGroup.setGroupName(device.getChildGroupName());
            deviceGroupMapper.insertDeviceGroup(childDeviceGroup);
        } else {
            childDeviceGroup.setParentId(parentDeviceGroup.getId());
            childDeviceGroup.setGroupType(device.getDeviceGroupTye());
            childDeviceGroup.setGroupName(device.getChildGroupName());
            deviceGroupMapper.updateDeviceGroup(childDeviceGroup);
        }
        return childDeviceGroup;
    }

    private void handleDensityHistory(List<HistoryData> deviceParamHistoryData) {
        for (HistoryData historyData : deviceParamHistoryData) {
            if (historyData.getDictValue().equals(DeviceCommandEnum.CURRENT_DENSITY.getCode())) {
                historyData.setStartTime(DateUtils.getNowDate());
                changeLastDensityHistory(historyData);
            }
        }
    }

    private void changeLastDensityHistory(HistoryData historyData) {
        Criteria criteria = new Criteria();
        criteria.andOperator(
                Criteria.where("deviceId").is(historyData.getDeviceId()),
                Criteria.where("dictValue").is(historyData.getDictValue())
        );
        Sort startSort = Sort.by(Sort.Order.desc("createTime"));
        List<HistoryData> densityList = mongoComponent.selectList(criteria, 1, startSort, HistoryData.class);
        if (densityList.size() > 0) {
            HistoryData lastDensity = densityList.get(0);
            Criteria updateCriteria = new Criteria();
            updateCriteria.andOperator(
                    Criteria.where("id").is(lastDensity.getId())
            );
            Update update = new Update().set("endTime", DateUtils.getNowDate());
            mongoComponent.updateFirst(updateCriteria, update, HistoryData.class);
        }
    }
}
